/* 
** (Copyright) sejishikong <sejishikong@263.net>
** Authors:    sejishikong <sejishikong@263.net>
**             Wei Lian <lianwei3@gmail.com> 
** Maintainer: Wei Lian
**    This program is free software; you can redistribute it and/or modify
**    it under the terms of the GNU General Public License Version 2 as
**    published by the Free Software Foundation;
**
**    This program is distributed in the hope that it will be useful,
**    but WITHOUT ANY WARRANTY; without even the implied warranty of
**    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**    GNU General Public License for more details.
**
**    You should have received a copy of the GNU General Public License
**    along with this program; if not, write to the Free Software
**    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**
*/
#include "header.h"
#include "sopfork.h"
#include "utils.h"
#include "tabwidget.h"
#include "mystatusbar.h"

SopFork::SopFork (TabWidget * tw, QWidget * parent, const char *name):
QHBox (parent, name),
tabwidget (tw)
{
   sop = new QProcess (this);
   connect (sop, SIGNAL (readyReadStdout ()), this, SLOT (parseStdout ()));
   connect (sop, SIGNAL (processExited ()), this, SLOT (onSopExit ()));

   snstatus = 0;

   echotimer = new QTimer (this);
   connect (echotimer, SIGNAL (timeout ()), this, SLOT (echo ()));

   ///row
   statusbar = new MyStatusBar (this);

   channelurl = "";
   strcpy (inport, "null");
   strcpy (outport, "null");
}


SopFork::~SopFork ()
{
   if (snstatus)
      delete snstatus;
   killSop ();
}

static QString
reduceLabelLength (const QString & s)
{
   uint maxLength = 8;
   QString str = s;
   if (str.length () <= maxLength)
      return str;
   str = str.left (maxLength);
//    str += "...";
   return str;
}


////fork new process
bool
SopFork::forkSop (QString channelurl, QString channelname, QString channeltype)
{
   this->channelurl = channelurl;
   this->channelname = channelname;
   this->channeltype = channeltype;

   tabwidget->setTabLabel (parentWidget (), reduceLabelLength (channelname));
   statusbar->showMessage (tr ("Connecting..."));

   int i, j;
   int sock;
   ///choose inport and outport number
   while (1) {
      i = rand () % (65536 - 3000) + 3000;	////3000 to 65535
      sock = connect_to_server ("127.0.0.1", i);
      if (sock == -1)
	 break;
      else if (sock >= 0)
	 ::close (sock);
   }
   sprintf (inport, "%d", i);
   while (1) {
      j = rand () % (65536 - 3000) + 3000;
      sock = connect_to_server ("127.0.0.1", j);
      if (sock == -1 && j != i)
	 break;
      else if (sock >= 0)
	 ::close (sock);
   }
   sprintf (outport, "%d", j);
   ////    
   sop->clearArguments ();
   sop->addArgument ("sp-sc");
   sop->addArgument (channelurl);
   sop->addArgument (inport);
   sop->addArgument (outport);
   return sop->start ();
}



////kill process
void
SopFork::killSop ()
{
/*    if (sop->isRunning()) {
//      sop->tryTerminate ();
	sop->kill();
    }*/
   char sopUrl[128] = "sp-sc ";
   strcat (sopUrl, channelurl.ascii ());
   strcat (sopUrl, " ");
   strcat (sopUrl, inport);
   strcat (sopUrl, " ");
   strcat (sopUrl, outport);
   killProcess (sopUrl);
}



/////////////slots
void
SopFork::onSopExit ()
{
   statusbar->showMessage ("");
   channelname = "";
   channelurl = "";
   tabwidget->setTabLabel (parentWidget (), tr ("record"));
}


void
SopFork::parseStdout ()
{
   QString str = QString (sop->readStdout ());

   if (snstatus == 0) {
      if (str.contains ("hook_sc") || str.contains ("downloadRate=")) {
	 //create socket
	 int sockfd = connect_to_server ("127.0.0.1", atoi (outport));
	 if (sockfd < 0) {
	    fprintf (stderr,
		     "failed to create socket, return err %d\n", sockfd);
	    return;
	 }
	 ///bind QSocketNotifier to socket
	 snstatus = new QSocketNotifier (sockfd, QSocketNotifier::Read, this);
	 connect (snstatus, SIGNAL (activated (int)),
		  SLOT (streamReady (int)));
	 write (sockfd, "state\ns\n", sizeof ("state\ns\n"));
	 write (sockfd, "state\ns\n", sizeof ("state\ns\n"));
      }
      else if (str.contains ("detect MTU"))
	 statusbar->showMessage (tr ("Waiting..."));
   }
}


void
SopFork::streamReady (int fd)
{
   char buff[64];
   memset (buff, 0, sizeof (buff));

   int red = 0, size, ret;
   size = sizeof (buff);
   while (1) {
      ret =::read (fd, buff + red, size);
      if (ret <= 0)		///server shutdown
      {
	 if (ret < 0)
	    perror ("status socketnotifier");
	 //close socket and delete socket noitifier
	 ::close (fd);
	 delete snstatus;
	 snstatus = 0;
	 ///stop timer
	 echotimer->stop ();
	 ///change statusbar interface
	 return;
      }
      if (strstr (buff, "\n"))
	 break;

      red += ret;
      size -= ret;
   }

   if (buff[0] != 10) {
      char *savept;
      strtok_r (buff, "\n", &savept);

      int value[6];
      value[0] = atoi (strtok_r (buff, " ", &savept));
      for (int i = 1; i < 6; i++) {
	 value[i] = atoi (strtok_r (NULL, " ", &savept));
	 if (i < 5)
	    value[i] = value[i] / 1024;
      }

      static const char format[][10] =
	 { "%d%%", "ur=%dk", "dr=%dk", "us=%dk", "ds=%dk",
	 "peers=%d"
      };

      QString str[6];

      for (int i = 0; i < 6; i++) {
	 sprintf (buff, format[i], value[i]);
	 str[i] = buff;
      }
      statusbar->showMessage (str);


   }
   else
      printf ("buff=10\n");

   ///singleshot
   echotimer->start (1000, true);
}


void
SopFork::echo ()
{
   if (tabwidget->indexOf (parentWidget ()) == tabwidget->currentPageIndex ()) {
      write (snstatus->socket (), "s\n", sizeof ("s\n"));
   }
   else
      echotimer->start (1000, true);
}
